package cn.core.sign.service.impl;

import cn.core.sign.ao.RoleAO;
import cn.core.sign.eo.AuthList;
import cn.core.sign.eo.Menu;
import cn.core.sign.eo.Role;
import cn.core.sign.mapper.AuthListMapper;
import cn.core.sign.mapper.RoleMapper;
import cn.core.sign.qo.AuthListQO;
import cn.core.sign.qo.RoleQO;
import cn.core.sign.service.intf.IRoleService;
import cn.core.sign.vo.RoleMenuTreeInfoVO;
import cn.core.sign.vo.RoleMenuTreeVO;
import cn.core.sign.vo.RoleVO;
import cn.core.tool.event.CoreDataEvent;
import cn.core.tool.exception.CoreException;
import cn.core.tool.util.CoreTool;
import cn.core.tool.util.CoreTree;
import cn.core.tool.util.Paging;
import cn.core.tool.util.Param;
import com.google.gson.reflect.TypeToken;
import lombok.extern.log4j.Log4j2;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;

/**
 * 角色 服务实现
 */
@Log4j2
@Primary
@Service
public class RoleServiceImpl implements IRoleService {

  @Resource
  private RoleMapper roleMapper;

  @Resource
  private AuthListMapper authListMapper;

  @Resource
  private ApplicationEventPublisher applicationEventPublisher;

  @Override
  @Transactional(propagation = Propagation.REQUIRED, readOnly = false)
  public Role save(Role eo) throws Exception {
    try {
      if (CoreTool.isNullEo(eo)) {
        throw new CoreException(CoreException.E_PARAM_ERR);
      }
      eo.setId(CoreTool.getUUID32());
      roleMapper.save(eo);
      return eo;
    } catch (Exception e) {
      if (log.isDebugEnabled()) {
        log.error(e.getMessage(), e);
      }
      throw e;
    }
  }

  @Override
  @Transactional(propagation = Propagation.REQUIRED, readOnly = false)
  public Collection<Role> saveBatch(Collection<Role> eos) throws Exception {
    try {
      if (CoreTool.isEmpty(eos)) {
        throw new CoreException(CoreException.E_PARAM_ERR);
      }
      for (Role eo : eos) {
        if (CoreTool.isNullEo(eo)) {
          throw new CoreException(CoreException.E_PARAM_ERR);
        }
        eo.setId(CoreTool.getUUID32());
      }
      roleMapper.saveBatch(new Paging<>(), eos);
      return eos;
    } catch (Exception e) {
      if (log.isDebugEnabled()) {
        log.error(e.getMessage(), e);
      }
      throw e;
    }
  }

  @Override
  @Transactional(propagation = Propagation.REQUIRED, readOnly = false)
  public Role update(Role eo) throws Exception {
    try {
      if (CoreTool.isNullEo(eo) || CoreTool.isNullStr(eo.getId())) {
        throw new CoreException(CoreException.E_PARAM_ERR);
      }
      Role oeo = roleMapper.pk(new RoleQO().setId(eo.getId()));
      if (CoreTool.isNullEo(oeo)) {
        throw new CoreException(CoreException.E_PARAM_ERR);
      }
//      if (eo.getVersions() != null ? !eo.getVersions().equals(oeo.getVersions()) : oeo.getVersions() != null ? true : false) {
//        throw new CoreException(CoreException.E_VERSIONS_ERR);
//      }
      roleMapper.update(eo);
      return eo;
    } catch (Exception e) {
      if (log.isDebugEnabled()) {
        log.error(e.getMessage(), e);
      }
      throw e;
    }
  }

  @Override
  @Transactional(propagation = Propagation.REQUIRED, readOnly = false)
  public Collection<Role> updateBatch(Collection<Role> eos) throws Exception {
    try {
      if (CoreTool.isEmpty(eos)) {
        throw new CoreException(CoreException.E_PARAM_ERR);
      }
      for (Role eo : eos) {
        if (CoreTool.isNullEo(eo) || CoreTool.isNullStr(eo.getId())) {
          throw new CoreException(CoreException.E_PARAM_ERR);
        }
        Role oeo = roleMapper.pk(new RoleQO().setId(eo.getId()));
        if (CoreTool.isNullEo(oeo)) {
          throw new CoreException(CoreException.E_PARAM_ERR);
        }
//        if (eo.getVersions() != null ? !eo.getVersions().equals(oeo.getVersions()) : oeo.getVersions() != null ? true : false) {
//          throw new CoreException(CoreException.E_VERSIONS_ERR);
//        }
      }
      roleMapper.updateBatch(new Paging<>(), eos);
      return eos;
    } catch (Exception e) {
      if (log.isDebugEnabled()) {
        log.error(e.getMessage(), e);
      }
      throw e;
    }
  }

  @Override
  @Transactional(propagation = Propagation.REQUIRED, readOnly = false)
  public void remove(Role eo) throws Exception {
    try {
      if (CoreTool.isNullEo(eo) || CoreTool.isNullStr(eo.getId())) {
        throw new CoreException(CoreException.E_PARAM_ERR);
      }
      roleMapper.remove(eo);
    } catch (Exception e) {
      if (log.isDebugEnabled()) {
        log.error(e.getMessage(), e);
      }
      throw e;
    }
  }

  @Override
  @Transactional(propagation = Propagation.REQUIRED, readOnly = false)
  public void removeBatch(Collection<Role> eos) throws Exception {
    try {
      if (CoreTool.isEmpty(eos)) {
        throw new CoreException(CoreException.E_PARAM_ERR);
      }
      LinkedHashSet<String> fkidAndIn = new LinkedHashSet<>();
      for (Role eo : eos) {
        if (CoreTool.isNullEo(eo) || CoreTool.isNullStr(eo.getId())) {
          throw new CoreException(CoreException.E_PARAM_ERR);
        }
        fkidAndIn.add(eo.getId());
      }
      if (CoreTool.isNotEmpty(fkidAndIn)) {
        authListMapper.removeQuery(new AuthListQO().setFkidAndIn(fkidAndIn));
      }
      roleMapper.removeBatch(eos);
    } catch (Exception e) {
      if (log.isDebugEnabled()) {
        log.error(e.getMessage(), e);
      }
      throw e;
    }
  }

  @Override
  public Long count(RoleQO qo) throws Exception {
    try {
      return roleMapper.count(qo);
    } catch (Exception e) {
      if (log.isDebugEnabled()) {
        log.error(e.getMessage(), e);
      }
      throw e;
    }
  }

  @Override
  public Role pk(RoleQO qo) throws Exception {
    try {
      if (CoreTool.isNullEo(qo) || CoreTool.isNullStr(qo.getId())) {
        throw new CoreException(CoreException.E_PARAM_ERR);
      }
      return roleMapper.pk(qo);
    } catch (Exception e) {
      if (log.isDebugEnabled()) {
        log.error(e.getMessage(), e);
      }
      throw e;
    }
  }

  @Override
  public Collection<Role> query(RoleQO qo) throws Exception {
    try {
      return roleMapper.query(qo);
    } catch (Exception e) {
      if (log.isDebugEnabled()) {
        log.error(e.getMessage(), e);
      }
      throw e;
    }
  }

  @Override
  public Paging<Role> paging(Param<RoleQO> param) throws Exception {
    try {
      if (CoreTool.isNullEo(param)) {
        throw new CoreException(CoreException.E_PARAM_ERR);
      }
      if (param.getPage() < 1 || param.getRows() < 1) {
        throw new CoreException(CoreException.E_PAGING_PARAM_ERR);
      }
      Paging<Role> paging = new Paging<>(param);
      if (CoreTool.isEmpty(param.getData()) || CoreTool.isNullEo(param.get())) {
        Long count = roleMapper.count(null);
        paging.setCount(count);
        if (count > 0) {
          if (count <= paging.getOffset()) {
            throw new CoreException(CoreException.E_PAGING_PARAM_ERR);
          }
          paging.setData(roleMapper.paging(paging, null));
        }
      } else {
        Long count = roleMapper.count(param.get());
        paging.setCount(count);
        if (count > 0) {
          if (count <= paging.getOffset()) {
            throw new CoreException(CoreException.E_PAGING_PARAM_ERR);
          }
          paging.setData(roleMapper.paging(paging, param.get()));
        }
      }
      return paging;
    } catch (Exception e) {
      if (log.isDebugEnabled()) {
        log.error(e.getMessage(), e);
      }
      throw e;
    }
  }

  @Override
  public Long countVo(RoleQO qo) throws Exception {
    try {
      return roleMapper.countVo(qo);
    } catch (Exception e) {
      if (log.isDebugEnabled()) {
        log.error(e.getMessage(), e);
      }
      throw e;
    }
  }

  @Override
  public RoleVO pkVo(RoleQO qo) throws Exception {
    try {
      if (CoreTool.isNullEo(qo) || CoreTool.isNullStr(qo.getId())) {
        throw new CoreException(CoreException.E_PARAM_ERR);
      }
      return roleMapper.pkVo(qo);
    } catch (Exception e) {
      if (log.isDebugEnabled()) {
        log.error(e.getMessage(), e);
      }
      throw e;
    }
  }

  @Override
  public Collection<RoleVO> queryVo(RoleQO qo) throws Exception {
    try {
      return roleMapper.queryVo(qo);
    } catch (Exception e) {
      if (log.isDebugEnabled()) {
        log.error(e.getMessage(), e);
      }
      throw e;
    }
  }

  @Override
  public Paging<RoleVO> pagingVo(Param<RoleQO> param) throws Exception {
    try {
      if (CoreTool.isNullEo(param)) {
        throw new CoreException(CoreException.E_PARAM_ERR);
      }
      if (param.getPage() < 1 || param.getRows() < 1) {
        throw new CoreException(CoreException.E_PAGING_PARAM_ERR);
      }
      Paging<RoleVO> paging = new Paging<>(param);
      if (CoreTool.isEmpty(param.getData()) || CoreTool.isNullEo(param.get())) {
        Long count = roleMapper.countVo(null);
        paging.setCount(count);
        if (count > 0) {
          if (count <= paging.getOffset()) {
            throw new CoreException(CoreException.E_PAGING_PARAM_ERR);
          }
          paging.setData(roleMapper.pagingVo(paging, null));
        }
      } else {
        Long count = roleMapper.countVo(param.get());
        paging.setCount(count);
        if (count > 0) {
          if (count <= paging.getOffset()) {
            throw new CoreException(CoreException.E_PAGING_PARAM_ERR);
          }
          paging.setData(roleMapper.pagingVo(paging, param.get()));
        }
      }
      return paging;
    } catch (Exception e) {
      if (log.isDebugEnabled()) {
        log.error(e.getMessage(), e);
      }
      throw e;
    }
  }

  @Override
  public Collection<String> getAuthListByRoleIdLoginSide(RoleAO qo) throws Exception {
    try {
      if (CoreTool.isNullEo(qo)) {
        throw new CoreException(CoreException.E_PARAM_ERR);
      }
      return roleMapper.getAuthListByRoleIdLoginSide(qo.getRoleId(), qo.getLoginSide());
    } catch (Exception e) {
      if (log.isDebugEnabled()) {
        log.error(e.getMessage(), e);
      }
      throw e;
    }
  }

  @Override
  @Transactional(propagation = Propagation.REQUIRED, readOnly = false)
  public Collection<AuthList> saveAuthList(RoleAO qo) throws Exception {
    try {
      if (CoreTool.isNullEo(qo)) {
        throw new CoreException(CoreException.E_PARAM_ERR);
      }
      LinkedHashSet<AuthList> authListSet = new LinkedHashSet<>();
      if (CoreTool.isNotEmpty(qo.getAuthList())) {
        for (String str : qo.getAuthList()) {
          authListSet.add(new AuthList()
              .setId(CoreTool.getUUID32())
              .setAuthKey(str)
              .setLoginSide(qo.getLoginSide())
              .setFkid(qo.getRoleId()));
        }
        authListMapper.removeQuery(new AuthListQO().setLoginSide(qo.getLoginSide()).setFkid(qo.getRoleId()));
        authListMapper.saveBatch(new Paging<>(), authListSet);
      } else {
        authListMapper.removeQuery(new AuthListQO().setLoginSide(qo.getLoginSide()).setFkid(qo.getRoleId()));
      }
      return authListSet;
    } catch (Exception e) {
      if (log.isDebugEnabled()) {
        log.error(e.getMessage(), e);
      }
      throw e;
    }
  }

  @Override
  public RoleMenuTreeVO getRoleMenuTreeByRoleIdLoginSide(RoleAO qo) throws Exception {
    try {
      if (CoreTool.isNullEo(qo)) {
        throw new CoreException(CoreException.E_PARAM_ERR);
      }
      RoleMenuTreeVO roleMenuTreeVO = new RoleMenuTreeVO();
      Collection<RoleMenuTreeInfoVO> roleMenuTreeInfoVOSet = roleMapper.getRoleMenuTreeInfoByRoleIdLoginSide(qo.getRoleId(), qo.getLoginSide());
      if (CoreTool.isNotEmpty(roleMenuTreeInfoVOSet)) {
        CoreDataEvent coreDataEvent = new CoreDataEvent("getDictValueMapInfoByDictKey", "menuType");
        applicationEventPublisher.publishEvent(coreDataEvent);
        LinkedHashMap<String, String> dictValueMapInfo = CoreTool.isNotNullStr(coreDataEvent.getData()) ? coreDataEvent.getData(new TypeToken<LinkedHashMap<String, String>>(){}) : new LinkedHashMap<String, String>();
        CoreTree<?> tree = null;
        Collection<CoreTree<?>> roleMenuTree = new ArrayList<>();
        Collection<CoreTree<?>> treeSet = new ArrayList<>();
        Collection<String> checkedKeys = new ArrayList<>();
        Collection<String> halfCheckedKeys = new ArrayList<>();
        Collection<String> expandedKeys = new ArrayList<>();
        Collection<String> allCheckedKeys = new ArrayList<>();
        for (RoleMenuTreeInfoVO eo : roleMenuTreeInfoVOSet) {
          treeSet.add(new CoreTree<RoleMenuTreeInfoVO>(eo)
              .setId(eo.getId())
              .setKey(eo.getMenuKey())
              .setName(eo.getMenuKey())
              .setTkey(eo.getMenuType())
              .setTitle(eo.getMenuName() + " - [" + dictValueMapInfo.get(eo.getMenuType()) + "]")
              .setValue(eo.getId())
              .setPid(eo.getPid()));
          if (CoreTool.isNotNullStr(eo.getAuthKey())) {
            if (CoreTool.isNotNullStr(eo.getCid())) {
              halfCheckedKeys.add(eo.getMenuKey());
            } else {
              checkedKeys.add(eo.getMenuKey());
            }
          }
          if (CoreTool.isNotNullStr(eo.getCid())) {
            expandedKeys.add(eo.getMenuKey());
          }
          allCheckedKeys.add(eo.getMenuKey());
        }
        tree = CoreTool.toTree(treeSet, true);
        roleMenuTree.add(tree);
        roleMenuTreeVO.setRoleMenuTree(roleMenuTree)
            .setCheckedKeys(checkedKeys)
            .setHalfCheckedKeys(halfCheckedKeys)
            .setExpandedKeys(expandedKeys)
            .setAllCheckedKeys(allCheckedKeys);
      }
      return roleMenuTreeVO;
    } catch (Exception e) {
      if (log.isDebugEnabled()) {
        log.error(e.getMessage(), e);
      }
      throw e;
    }
  }

}
